home *** CD-ROM | disk | FTP | other *** search
/ SuperHack / SuperHack CD.bin / CODING / CPP / WFC010.ZIP / SRC / CSVCMGR.CPP < prev    next >
C/C++ Source or Header  |  1995-12-07  |  18KB  |  675 lines

  1. #include <wfc.h>
  2. #pragma hdrstop
  3.  
  4. /*
  5. ** Author: Samuel R. Blackburn
  6. ** CI$: 76300,326
  7. ** Internet: sammy@sed.csc.com
  8. **
  9. ** You can use it any way you like as long as you don't try to sell it.
  10. **
  11. ** Any attempt to sell WFC in source code form must have the permission
  12. ** of the original author. You can produce commercial executables with
  13. ** WFC but you can't sell WFC.
  14. **
  15. ** Copyright, 1995, Samuel R. Blackburn
  16. **
  17. ** $Workfile: $
  18. ** $Revision: $
  19. ** $Modtime: $
  20. */
  21.  
  22. #if defined( _DEBUG )
  23. #undef THIS_FILE
  24. static char BASED_CODE THIS_FILE[] = __FILE__;
  25. #define new DEBUG_NEW
  26. #endif
  27.  
  28. CServiceControlManager::CServiceControlManager()
  29. {
  30.    m_Initialize();
  31. }
  32.  
  33. CServiceControlManager::~CServiceControlManager()
  34. {
  35.    Close();
  36.  
  37.    if ( m_Buffer != NULL )
  38.    {
  39.       delete [] m_Buffer;
  40.       m_Buffer     = NULL;
  41.       m_BufferSize = 0;
  42.    }
  43. }
  44.  
  45. void CServiceControlManager::Close( void )
  46. {
  47.    if ( m_ManagerHandle != NULL )
  48.    {
  49.       if ( ::CloseServiceHandle( m_ManagerHandle ) == FALSE )
  50.       {
  51.          m_ErrorCode = ::GetLastError();
  52.       }
  53.  
  54.       m_ManagerHandle = NULL;
  55.    }
  56. }
  57.  
  58. BOOL CServiceControlManager::Continue( LPCTSTR service_name )
  59. {
  60.    ASSERT( service_name != NULL );
  61.  
  62.    if ( m_ManagerHandle == NULL )
  63.    {
  64.       m_ErrorCode = ERROR_INVALID_HANDLE;
  65.       return( FALSE );
  66.    }
  67.  
  68.    if ( service_name == NULL )
  69.    {
  70.       m_ErrorCode = ERROR_INVALID_HANDLE;
  71.       return( FALSE );
  72.    }
  73.  
  74.    SC_HANDLE service_handle = ::OpenService( m_ManagerHandle, service_name, SERVICE_PAUSE_CONTINUE );
  75.  
  76.    if ( service_handle == (SC_HANDLE) NULL )
  77.    {
  78.       m_ErrorCode = ::GetLastError();
  79.       return( FALSE );
  80.    }
  81.  
  82.    SERVICE_STATUS service_status;
  83.  
  84.    ::ZeroMemory( &service_status, sizeof( service_status ) );
  85.  
  86.    BOOL return_value = ::ControlService( service_handle, SERVICE_CONTROL_CONTINUE, &service_status );
  87.  
  88.    if ( return_value != TRUE )
  89.    {
  90.       m_ErrorCode = ::GetLastError();
  91.    }
  92.  
  93.    ::CloseServiceHandle( service_handle );
  94.  
  95.    return( return_value );
  96. }
  97.  
  98. BOOL CServiceControlManager::EnumerateStatus( DWORD state, DWORD type )
  99. {
  100.    /*
  101.    ** For GetNext() calls
  102.    */
  103.  
  104.    if ( m_ManagerHandle == NULL )
  105.    {
  106.       m_ErrorCode = ERROR_INVALID_HANDLE;
  107.       return( FALSE );
  108.    }
  109.  
  110.    if ( m_Buffer == NULL )
  111.    {
  112.       m_BufferSize = 128 * sizeof( ENUM_SERVICE_STATUS );
  113.  
  114.       m_Buffer = (ENUM_SERVICE_STATUS *) new BYTE[ m_BufferSize ];
  115.  
  116.       if ( m_Buffer == NULL )
  117.       {
  118.          m_BufferSize = 0;
  119.          m_ErrorCode = ::GetLastError();
  120.          return( FALSE );
  121.       }
  122.    }
  123.  
  124.    DWORD number_of_bytes_needed      = 0;
  125.    DWORD number_of_services_returned = 0;
  126.    DWORD resume_handle               = 0;
  127.  
  128.    if ( ::EnumServicesStatus( m_ManagerHandle,
  129.                               type,
  130.                               state,
  131.                               m_Buffer,
  132.                               m_BufferSize,
  133.                               &number_of_bytes_needed,
  134.                               &number_of_services_returned,
  135.                               &resume_handle ) == TRUE )
  136.    {
  137.       m_CurrentEntryNumber = 0;
  138.       m_NumberOfEntries    = number_of_services_returned;
  139.  
  140.       return( TRUE );
  141.    }
  142.  
  143.    m_ErrorCode = ::GetLastError();
  144.  
  145.    if ( m_ErrorCode == ERROR_MORE_DATA )
  146.    {
  147.       delete [] m_Buffer;
  148.  
  149.       m_Buffer = (ENUM_SERVICE_STATUS *) new BYTE[ number_of_bytes_needed ];
  150.  
  151.       if ( m_Buffer != NULL )
  152.       {
  153.          m_BufferSize = number_of_bytes_needed;
  154.       }
  155.       else
  156.       {
  157.          m_ErrorCode = ::GetLastError();
  158.          return( FALSE );
  159.       }
  160.  
  161.       number_of_bytes_needed      = 0;
  162.       number_of_services_returned = 0;
  163.       resume_handle               = 0;
  164.  
  165.       if ( ::EnumServicesStatus( m_ManagerHandle,
  166.                                  type,
  167.                                  state,
  168.                                  m_Buffer,
  169.                                  m_BufferSize,
  170.                                 &number_of_bytes_needed,
  171.                                 &number_of_services_returned,
  172.                                 &resume_handle ) == TRUE )
  173.       {
  174.          m_CurrentEntryNumber = 0;
  175.          m_NumberOfEntries    = number_of_services_returned;
  176.  
  177.          return( TRUE );
  178.       }
  179.       else
  180.       {
  181.          m_CurrentEntryNumber = 0;
  182.          m_NumberOfEntries    = 0;
  183.  
  184.          m_ErrorCode = ::GetLastError();
  185.  
  186.          return( FALSE );
  187.       }
  188.    }
  189.  
  190.    return( FALSE );
  191. }
  192.  
  193. DWORD CServiceControlManager::GetErrorCode( void ) const
  194. {
  195.    return( m_ErrorCode );
  196. }
  197.  
  198. BOOL CServiceControlManager::GetNext( CServiceNameAndStatus& status )
  199. {
  200.    if ( m_CurrentEntryNumber < m_NumberOfEntries )
  201.    {
  202.       status.Copy( &m_Buffer[ m_CurrentEntryNumber ] );
  203.       m_CurrentEntryNumber++;
  204.       return( TRUE );
  205.    }
  206.  
  207.    return( FALSE );
  208. }
  209.  
  210. BOOL CServiceControlManager::Install( LPCTSTR service_name, LPCTSTR friendly_name, LPCTSTR name_of_executable_file )
  211. {
  212.    ASSERT( service_name            != NULL );
  213.    ASSERT( friendly_name           != NULL );
  214.    ASSERT( name_of_executable_file != NULL );
  215.  
  216.    if ( service_name            == (LPCTSTR) NULL ||
  217.         friendly_name           == (LPCTSTR) NULL ||
  218.         name_of_executable_file == (LPCTSTR) NULL ||
  219.         m_ManagerHandle         == NULL )
  220.    {
  221.       m_ErrorCode == ERROR_INVALID_HANDLE;
  222.       return( FALSE );
  223.    }
  224.  
  225.    TRACE( "CServiceControlManager::Install()\n" );
  226.  
  227.    DWORD supported_types = EVENTLOG_ERROR_TYPE       | 
  228.                            EVENTLOG_WARNING_TYPE     |
  229.                            EVENTLOG_INFORMATION_TYPE |
  230.                            EVENTLOG_AUDIT_SUCCESS    |
  231.                            EVENTLOG_AUDIT_FAILURE;
  232.  
  233.    CEventLog event_log;
  234.  
  235.    TRACE( "CServiceControlManager::Install(), Creating Application log\n" );
  236.  
  237.    if ( event_log.CreateApplicationLog( service_name, name_of_executable_file, supported_types ) != TRUE )
  238.    {
  239.       return( FALSE );
  240.    }
  241.  
  242.    TRACE( "CServiceControlManager::Install(), Registering Source\n" );
  243.  
  244.    if ( event_log.RegisterSource( service_name ) != TRUE )
  245.    {
  246.       return( FALSE );
  247.    }
  248.  
  249.    SC_HANDLE service_handle = (SC_HANDLE) NULL;
  250.    
  251.    TRACE( "CServiceControlManager::Install(), Creating Service\n" );
  252.  
  253.    service_handle = ::CreateService( m_ManagerHandle,
  254.                                      service_name,
  255.                                      friendly_name,
  256.                                      SERVICE_ALL_ACCESS,
  257.                                      SERVICE_WIN32_OWN_PROCESS,
  258.                                      SERVICE_DEMAND_START,
  259.                                      SERVICE_ERROR_NORMAL,
  260.                                      name_of_executable_file,
  261.                                      NULL,
  262.                                      NULL,
  263.                                      "EventLog\0\0",
  264.                                      NULL,
  265.                                      NULL );
  266.  
  267.    TRACE( "CServiceControlManager::Install(), CreateService() returned\n" );
  268.  
  269.    if ( service_handle == (SC_HANDLE) NULL )
  270.    {
  271.       TRACE( "CServiceControlManager::Install(), service_handle == NULL\n" );
  272.  
  273.       m_ErrorCode = ::GetLastError();
  274.  
  275.       LPVOID message_buffer = (LPVOID) NULL;
  276.  
  277.       TRACE( "CServiceControlManager::Install(), Calling FormatMessage()\n" );
  278.  
  279.       ::FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
  280.                        NULL,
  281.                        m_ErrorCode,
  282.                        MAKELANGID( LANG_ENGLISH, SUBLANG_ENGLISH_US ),
  283.              (LPTSTR) &message_buffer,
  284.                        0,
  285.                        NULL );
  286.  
  287.       TRACE( "CServiceControlManager::Install(), FormatMessage() returned\n" );
  288.  
  289.       if ( message_buffer != NULL )
  290.       {
  291.          TCHAR temp_string[ 255 ];
  292.  
  293.          TRACE( "CServiceControlManager::Install(), Calling wsprintf()\n" );
  294.          ::wsprintf( temp_string, "Can't create service because %s at line %d of CSvcMgr.cpp", message_buffer, __LINE__ );
  295.          TRACE( "CServiceControlManager::Install(), Calling ReportError()\n" );
  296.  
  297.          event_log.ReportError( temp_string );
  298.  
  299.       TRACE( "CServiceControlManager::Install(), Calling LocalFree()\n" );
  300.          ::LocalFree( message_buffer );
  301.       TRACE( "CServiceControlManager::Install(), LocalFree returned()\n" );
  302.       }
  303.  
  304.       TRACE( "CServiceControlManager::Install(), returning FALSE\n" );
  305.       return( FALSE );
  306.    }
  307.  
  308.    TRACE( "CServiceControlManager::Install(), Closeing service handle\n" );
  309.  
  310.    ::CloseServiceHandle( service_handle );
  311.    service_handle = (SC_HANDLE) NULL;
  312.  
  313.    /*
  314.    ** We successfully installed a new service, this is something we should log
  315.    */
  316.  
  317.    TCHAR user_name[ 2048 ];
  318.    TCHAR temp_string[ 2100 ];
  319.  
  320.    DWORD size_of_user_name = sizeof( user_name );
  321.  
  322.    ::ZeroMemory( user_name,   size_of_user_name     );
  323.    ::ZeroMemory( temp_string, sizeof( temp_string ) );
  324.  
  325.    TRACE( "CServiceControlManager::Install(), Getting User Name\n" );
  326.  
  327.    ::GetUserName( user_name, &size_of_user_name );
  328.  
  329.    TRACE( "CServiceControlManager::Install(), wsprintf()\n" );
  330.  
  331.    ::wsprintf( temp_string, "Service successfully installed by %s", user_name );
  332.  
  333.    TRACE( "CServiceControlManager::Install(), reporting\n" );
  334.  
  335.    event_log.ReportInformation( temp_string );
  336.  
  337.    TRACE( "CServiceControlManager::Install(), returning\n" );
  338.    return( TRUE );
  339. }
  340.  
  341. void CServiceControlManager::m_Initialize( void )
  342. {
  343.    m_ManagerHandle      = NULL;
  344.    m_ErrorCode          = 0;
  345.    m_Buffer             = NULL;
  346.    m_BufferSize         = 0;
  347.    m_CurrentEntryNumber = 0;
  348.    m_NumberOfEntries    = 0;
  349. }
  350.  
  351. BOOL CServiceControlManager::Open( DWORD what_to_open, LPCTSTR database_name, LPCTSTR machine_name )
  352. {
  353.    /*
  354.    ** database_name can be NULL
  355.    */
  356.  
  357.    if ( m_ManagerHandle != NULL )
  358.    {
  359.       Close();
  360.    }
  361.  
  362.    if ( machine_name == NULL )
  363.    {
  364.       m_MachineName.Empty(); // Should go and get our machine's name
  365.    }
  366.    else
  367.    {
  368.       m_MachineName = machine_name;
  369.    }
  370.  
  371.    m_ManagerHandle = ::OpenSCManager( machine_name, database_name, what_to_open );
  372.  
  373.    if ( m_ManagerHandle == NULL )
  374.    {
  375.       m_ErrorCode = ::GetLastError();
  376.       return( FALSE );
  377.    }
  378.    else
  379.    {
  380.       return( TRUE );
  381.    }
  382. }
  383.  
  384. BOOL CServiceControlManager::Pause( LPCTSTR service_name )
  385. {
  386.    ASSERT( service_name != NULL );
  387.  
  388.    if ( m_ManagerHandle == NULL )
  389.    {
  390.       m_ErrorCode = ERROR_INVALID_HANDLE;
  391.       return( FALSE );
  392.    }
  393.  
  394.    if ( service_name == NULL )
  395.    {
  396.       m_ErrorCode = ERROR_INVALID_HANDLE;
  397.       return( FALSE );
  398.    }
  399.  
  400.    SC_HANDLE service_handle = ::OpenService( m_ManagerHandle, service_name, SERVICE_PAUSE_CONTINUE );
  401.  
  402.    if ( service_handle == (SC_HANDLE) NULL )
  403.    {
  404.       m_ErrorCode = ::GetLastError();
  405.       return( FALSE );
  406.    }
  407.  
  408.    SERVICE_STATUS service_status;
  409.  
  410.    ::ZeroMemory( &service_status, sizeof( service_status ) );
  411.  
  412.    BOOL return_value = ::ControlService( service_handle, SERVICE_CONTROL_PAUSE, &service_status );
  413.  
  414.    if ( return_value != TRUE )
  415.    {
  416.       m_ErrorCode = ::GetLastError();
  417.    }
  418.  
  419.    ::CloseServiceHandle( service_handle );
  420.  
  421.    return( return_value );
  422. }
  423.  
  424. BOOL CServiceControlManager::Remove( LPCTSTR service_name )
  425. {
  426.    ASSERT( service_name != NULL );
  427.  
  428.    if ( service_name == (LPCTSTR) NULL || m_ManagerHandle == NULL )
  429.    {
  430.       m_ErrorCode = ERROR_INVALID_HANDLE;
  431.       return( FALSE );
  432.    }
  433.  
  434.    SC_HANDLE service_handle = (SC_HANDLE) NULL;
  435.  
  436.    service_handle = ::OpenService( m_ManagerHandle, service_name, SERVICE_ALL_ACCESS );
  437.  
  438.    if ( service_handle == (SC_HANDLE) NULL )
  439.    {
  440.       m_ErrorCode = ::GetLastError();
  441.       return( FALSE );
  442.    }
  443.  
  444.    /*
  445.    ** We're gonna delete the service, this is something we should record
  446.    */
  447.  
  448.    {
  449.       TCHAR user_name[ 2048 ];
  450.       TCHAR temp_string[ 2100 ];
  451.  
  452.       DWORD size_of_user_name = sizeof( user_name );
  453.  
  454.       ::ZeroMemory( user_name,   size_of_user_name     );
  455.       ::ZeroMemory( temp_string, sizeof( temp_string ) );
  456.  
  457.       ::GetUserName( user_name, &size_of_user_name );
  458.  
  459.       ::wsprintf( temp_string, "Service being removed by %s", user_name );
  460.  
  461.       CEventLog event_log( service_name );
  462.  
  463.       event_log.ReportInformation( temp_string );
  464.    }
  465.  
  466.    BOOL return_value = ::DeleteService( service_handle );
  467.  
  468.    if ( return_value != TRUE )
  469.    {
  470.       m_ErrorCode = ::GetLastError();
  471.  
  472.       /*
  473.       ** We couldn't delete the service, let's record why...
  474.       */
  475.  
  476.       LPVOID message_buffer = (LPVOID) NULL;
  477.  
  478.       ::FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
  479.                        NULL,
  480.                        m_ErrorCode,
  481.                        MAKELANGID( LANG_ENGLISH, SUBLANG_ENGLISH_US ),
  482.              (LPTSTR) &message_buffer,
  483.                        0,
  484.                        NULL );
  485.  
  486.       if ( message_buffer != NULL )
  487.       {
  488.          TCHAR temp_string[ 255 ];
  489.  
  490.          ::wsprintf( temp_string, "Can't delete service because %s", message_buffer );
  491.  
  492.          CEventLog event_log( service_name );
  493.          event_log.ReportError( temp_string );
  494.  
  495.          ::LocalFree( message_buffer );
  496.       }
  497.  
  498.       return( FALSE );
  499.    }
  500.  
  501.    /*
  502.    ** Now that we've deleted the service, we need to remove it from the event logger
  503.    */
  504.  
  505.    CEventLog event_log;
  506.  
  507.    event_log.DeleteApplicationLog( service_name );
  508.  
  509.    return( TRUE );
  510. }
  511.  
  512. BOOL CServiceControlManager::Start( LPCTSTR service_name, DWORD service_argc, LPCTSTR *service_argv )
  513. {
  514.    ASSERT( service_name != NULL );
  515.  
  516.    if ( m_ManagerHandle == NULL )
  517.    {
  518.       m_ErrorCode = ERROR_INVALID_HANDLE;
  519.       return( FALSE );
  520.    }
  521.  
  522.    if ( service_name == NULL )
  523.    {
  524.       m_ErrorCode = ERROR_INVALID_HANDLE;
  525.       return( FALSE );
  526.    }
  527.  
  528.    SC_HANDLE service_handle = ::OpenService( m_ManagerHandle, service_name, SERVICE_START );
  529.  
  530.    if ( service_handle == (SC_HANDLE) NULL )
  531.    {
  532.       m_ErrorCode = ::GetLastError();
  533.       return( FALSE );
  534.    }
  535.  
  536.    BOOL return_value = ::StartService( service_handle, service_argc, service_argv );
  537.  
  538.    if ( return_value != TRUE )
  539.    {
  540.       m_ErrorCode = ::GetLastError();
  541.    }
  542.  
  543.    ::CloseServiceHandle( service_handle );
  544.  
  545.    return( return_value );
  546. }
  547.  
  548. BOOL CServiceControlManager::Stop( LPCTSTR service_name )
  549. {
  550.    ASSERT( service_name != NULL );
  551.  
  552.    if ( m_ManagerHandle == NULL )
  553.    {
  554.       m_ErrorCode = ERROR_INVALID_HANDLE;
  555.       return( FALSE );
  556.    }
  557.  
  558.    if ( service_name == NULL )
  559.    {
  560.       m_ErrorCode = ERROR_INVALID_HANDLE;
  561.       return( FALSE );
  562.    }
  563.  
  564.    SC_HANDLE service_handle = ::OpenService( m_ManagerHandle, service_name, SERVICE_STOP );
  565.  
  566.    if ( service_handle == (SC_HANDLE) NULL )
  567.    {
  568.       m_ErrorCode = ::GetLastError();
  569.       return( FALSE );
  570.    }
  571.  
  572.    SERVICE_STATUS service_status;
  573.  
  574.    ::ZeroMemory( &service_status, sizeof( service_status ) );
  575.  
  576.    BOOL return_value = ::ControlService( service_handle, SERVICE_CONTROL_STOP, &service_status );
  577.  
  578.    if ( return_value != TRUE )
  579.    {
  580.       m_ErrorCode = ::GetLastError();
  581.    }
  582.  
  583.    ::CloseServiceHandle( service_handle );
  584.  
  585.    return( return_value );
  586. }
  587.  
  588. CServiceNameAndStatusA::CServiceNameAndStatusA()
  589. {
  590.    Empty();
  591. }
  592.  
  593. CServiceNameAndStatusA::~CServiceNameAndStatusA()
  594. {
  595.    Empty();
  596. }
  597.  
  598. void CServiceNameAndStatusA::Copy( const _ENUM_SERVICE_STATUSA *source_p )
  599. {
  600.    ASSERT( source_p != NULL );
  601.  
  602.    if ( source_p == NULL )
  603.    {
  604.       Empty();
  605.       return;
  606.    }
  607.  
  608.    lpServiceName                           = source_p->lpServiceName;
  609.    lpDisplayName                           = source_p->lpDisplayName;
  610.    ServiceStatus.dwServiceType             = source_p->ServiceStatus.dwServiceType;
  611.    ServiceStatus.dwCurrentState            = source_p->ServiceStatus.dwCurrentState;
  612.    ServiceStatus.dwControlsAccepted        = source_p->ServiceStatus.dwControlsAccepted;
  613.    ServiceStatus.dwWin32ExitCode           = source_p->ServiceStatus.dwWin32ExitCode;
  614.    ServiceStatus.dwServiceSpecificExitCode = source_p->ServiceStatus.dwServiceSpecificExitCode;
  615.    ServiceStatus.dwCheckPoint              = source_p->ServiceStatus.dwCheckPoint;
  616.    ServiceStatus.dwWaitHint                = source_p->ServiceStatus.dwWaitHint;
  617. }
  618.  
  619. void CServiceNameAndStatusA::Empty( void )
  620. {
  621.    lpServiceName                           = NULL;
  622.    lpDisplayName                           = NULL;
  623.    ServiceStatus.dwServiceType             = 0;
  624.    ServiceStatus.dwCurrentState            = 0;
  625.    ServiceStatus.dwControlsAccepted        = 0;
  626.    ServiceStatus.dwWin32ExitCode           = 0;
  627.    ServiceStatus.dwServiceSpecificExitCode = 0;
  628.    ServiceStatus.dwCheckPoint              = 0;
  629.    ServiceStatus.dwWaitHint                = 0;
  630. }
  631.  
  632. CServiceNameAndStatusW::CServiceNameAndStatusW()
  633. {
  634.    Empty();
  635. }
  636.  
  637. CServiceNameAndStatusW::~CServiceNameAndStatusW()
  638. {
  639.    Empty();
  640. }
  641.  
  642. void CServiceNameAndStatusW::Copy( const _ENUM_SERVICE_STATUSW *source_p )
  643. {
  644.    ASSERT( source_p != NULL );
  645.  
  646.    if ( source_p == NULL )
  647.    {
  648.       Empty();
  649.       return;
  650.    }
  651.  
  652.    lpServiceName                           = source_p->lpServiceName;
  653.    lpDisplayName                           = source_p->lpDisplayName;
  654.    ServiceStatus.dwServiceType             = source_p->ServiceStatus.dwServiceType;
  655.    ServiceStatus.dwCurrentState            = source_p->ServiceStatus.dwCurrentState;
  656.    ServiceStatus.dwControlsAccepted        = source_p->ServiceStatus.dwControlsAccepted;
  657.    ServiceStatus.dwWin32ExitCode           = source_p->ServiceStatus.dwWin32ExitCode;
  658.    ServiceStatus.dwServiceSpecificExitCode = source_p->ServiceStatus.dwServiceSpecificExitCode;
  659.    ServiceStatus.dwCheckPoint              = source_p->ServiceStatus.dwCheckPoint;
  660.    ServiceStatus.dwWaitHint                = source_p->ServiceStatus.dwWaitHint;
  661. }
  662.  
  663. void CServiceNameAndStatusW::Empty( void )
  664. {
  665.    lpServiceName                           = NULL;
  666.    lpDisplayName                           = NULL;
  667.    ServiceStatus.dwServiceType             = 0;
  668.    ServiceStatus.dwCurrentState            = 0;
  669.    ServiceStatus.dwControlsAccepted        = 0;
  670.    ServiceStatus.dwWin32ExitCode           = 0;
  671.    ServiceStatus.dwServiceSpecificExitCode = 0;
  672.    ServiceStatus.dwCheckPoint              = 0;
  673.    ServiceStatus.dwWaitHint                = 0;
  674. }
  675.